import BMapGL from 'BMapGL'

// 点位层
const MARKER_KEY = Symbol()
// 轨迹层
const POLYLINE_KEY = Symbol()
// label层
const LABEL_KEY = Symbol()


export default class MapContainer {

  constructor(options = {}) {
    this.options = Object.assign({}, options)
    this.layersMap = {}
    this.initMap()
  }

  initMap() {
    const { target, center = [113.151737, 27.835806], zoom = 15 } = this.options
    if (!target) {
      console.error('请选择容器')
      return
    }
    const map = new BMapGL.Map(target)
    const point = new BMapGL.Point(...center)
    map.centerAndZoom(point, zoom)
    map.enableScrollWheelZoom(true)
    this.map = map
  }

  /**
   * 添加点
   * @param {({iconUrl:string,iconSize:number[],location:number[],attributes:Object}[] | {iconUrl:string,iconSize:number[],location:number[],attributes:Object})}markers 点位
   * @param {{clickCallBack:function}} options 配置项
   */
  addMarkers(markers, options = {}) {
    this.clearMarkers()

    const _markers = this._addMarkers(markers, options = {})

    this._setLayer(MARKER_KEY, _markers)
  }

  /**
   * 组件内部使用
   * @param {({iconUrl:string,iconSize:number[],location:number[],attributes:Object}[] | {iconUrl:string,iconSize:number[],location:number[],attributes:Object})}markers 点位
   * @param {{clickCallBack:function}} options 配置项
   */
  _addMarkers(markers, options = {}) {
    const markersArr = markers instanceof Array ? markers : [markers]
    let _markers = []
    markersArr.forEach(marker => {
      const { iconUrl, iconSize = [52, 26], location, attributes = {} } = marker
      if (!location) {
        return
      }
      const pt = new BMapGL.Point(...location)
      const newMarker = iconUrl ? new BMapGL.Marker(pt, {
        icon: new BMapGL.Icon(iconUrl, new BMapGL.Size(...iconSize))
      }) : new BMapGL.Marker(pt)
      newMarker.attributes = attributes
      this.map.addOverlay(newMarker)
      if (options.clickCallBack) {
        newMarker.addEventListener('click', options.clickCallBack)
      }
      _markers.push(newMarker)
    })


    return _markers
  }

  /**
   * 清除点
   * */
  clearMarkers() {
    this._removeLayer(MARKER_KEY)
  }

  /**
   * 添加地图弹窗
   * @param {number[]} center 弹窗中心点
   * @param {Object} el 弹窗体
   * @param {Object} infoOptions 弹窗配置
   * */
  openInfoWindow(center, el, infoOptions = {}) {
    const infoWindow = new BMapGL.InfoWindow(el, {
      ...infoOptions
    })
    this.map.openInfoWindow(infoWindow, center)
    this.map.centerAndZoom(new BMapGL.Point(...this._toCenter(center)), 16)
  }

  /**
   * 关闭弹窗
   * */
  closeInfoWindow() {
    this.map.closeInfoWindow()
  }

  /**
   * 绘制线
   * */
  drawPloyLines(lines, linesOption = {}, callback) {
    this.clearPloyLines()
    const _lines = lines instanceof Array ? lines : [lines]
    const _ployLine = []
    _lines.forEach(line => {
      const points = []

      const addLabels = (labels, labelOption) => {
        const _labels = this._addLabels(labels, labelOption)
        _ployLine.push(..._labels)
      }

      const addMarkers = (markers, markerOption) => {
        const _markers = this._addLabels(markers, markerOption)
        _ployLine.push(..._markers)
      }

      line.forEach((point, index) => {
        points.push(new BMapGL.Point(...this._toCenter(point)))
        callback && callback({ point, index }, { addLabels, addMarkers })
      })

      const polyline = new BMapGL.Polyline(points, {
        strokeColor: 'blue',
        strokeWeight: 2,
        strokeOpacity: 0.5, ...linesOption
      })

      this.map.addOverlay(polyline)
      _ployLine.push(polyline)
    })

    this._setLayer(POLYLINE_KEY, _ployLine)
  }

  /**
   * 清除线
   * */
  clearPloyLines() {
    this._removeLayer(POLYLINE_KEY)
  }

  /**
   * 绘制label
   * @param {({location:number[],label:string} | {location:number[],label:string})} labels label集合
   * */
  addLabels(labels, labelOption) {
    this.clearLabels()

    const _labels = this._addLabels(labels, labelOption)

    this._setLayer(LABEL_KEY, _labels)
  }

  /**
   * 清除label
   * */
  clearLabels() {
    this._removeLayer(LABEL_KEY)
  }

  /**
   * 内部绘制label
   * @param {({location:number[],label:string} | {location:number[],label:string})} labels label集合
   * */
  _addLabels(labels, labelOption = {}) {
    const _labelsArr = labels instanceof Array ? labels : [labels]
    const _labels = []

    _labelsArr.forEach(_label => {
      const label = new BMapGL.Label(_label.label, {
        position: new BMapGL.Point(...this._toCenter(_label.location)),
        ...labelOption,
        offset: new BMapGL.Size(...(labelOption.offset || [30, -30]))
      })

      label.setStyle(labelOption.style || {
        color: 'blue',
        borderRadius: '5px',
        borderColor: '#ccc',
        padding: '10px',
        fontSize: '16px',
        height: '30px',
        lineHeight: '30px',
        fontFamily: '微软雅黑'
      })

      this.map.addOverlay(label)

      _labels.push(label)
    })

    return _labels
  }

  // 转换经纬度
  _toCenter(data, type = 'array') {
    if (type === 'array') {
      if (!Array.isArray(data)) {
        if (data.lng && data.lat) {
          return [data.lng, data.lat]
        } else if (data.longitude && data.latitude) {
          return [data.longitude, data.latitude]
        }
      }
    } else {
      if (data instanceof Object && Array.isArray(data) && data.length === 2) {
        return {
          lng: data[0],
          lat: data[1]
        }
      }
    }
    return data
  }

  /**
   * 设置图层
   * @param name 图层名字
   * @param {(Object[] | Object)} data 数据
   */
  _setLayer(name, data) {
    if (data instanceof Array) {
      this.layersMap[name] = data
    } else if (data instanceof Object) {
      this.layersMap[name] = [data]
    } else {
      this.layersMap[name] && delete this.layersMap[name]
    }
  }

  /**
   * 删除图层
   * @param name 图层名字
   */
  _removeLayer(name) {
    if (this.layersMap[name] instanceof Array && this.layersMap[name].length) {
      this.layersMap[name].forEach(layer => {
        this.map.removeOverlay(layer)
      })
    }
    this._setLayer(name, null)
  }
}
